package app.caihan.wanandroid.ui.main

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import app.caihan.scframe.api.retrofit2.ExceptionHandle
import app.caihan.scframe.api.retrofit2.checkResult
import app.caihan.scframe.api.retrofit2.doFailure
import app.caihan.scframe.api.retrofit2.doSuccess
import app.caihan.scframe.constant.DEBUG_TAG
import app.caihan.wanandroid.base.WanBaseViewModel
import app.caihan.wanandroid.model.ScWanAndroidFactory
import app.caihan.wanandroid.model.bean.BannerBean
import app.caihan.wanandroid.model.bean.PageList
import com.blankj.utilcode.util.LogUtils
import com.scwang.smart.refresh.layout.api.RefreshLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext

/**
 *
 *
 * @author Seven-C
 * @date 2020/8/15
 */
class MainFragmentModel : WanBaseViewModel() {

    private val repository by lazy { ScWanAndroidFactory.makeWanRepository() }

    val text: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // 私有的 MutableLiveData 可变的，对内访问
    private val _articleList: MutableLiveData<PageList> by lazy {
        MutableLiveData<PageList>()
    }
    private val _banners: MutableLiveData<List<BannerBean>> by lazy {
        MutableLiveData<List<BannerBean>>()
    }

    // 对外暴露不可变的 LiveData，只能查询
    val articleList: LiveData<PageList> = _articleList
    val banners: LiveData<List<BannerBean>> = _banners

    val onRefreshListener: (RefreshLayout) -> Unit = {
        launchUI {
            getBannersDb2(true)
            getArticleList2(true)
            _articleList.value?.apply {
                finishRefresh(this)
            }
        }
    }

    val onLoadMoreListener: (RefreshLayout) -> Unit = {
        launchUI {
            getArticleList2(false)
            _articleList.value?.apply {
                finishRefresh(this)
            }
        }
    }


    private suspend fun getArticleList2(isRefresh: Boolean = false) {
        var page = 0
        if (!isRefresh) {
            _articleList.value?.apply {
                page = curPage + 1
            }
        }
        repository.getArticleList2(page)
            .checkResult(
                onSuccess = {
                    _articleList.value = it
                }, onError = {
                    LogUtils.dTag(DEBUG_TAG, "getArticleList2 onError $it")
                }
            )
    }

    private suspend fun getBannersDb2(isRefresh: Boolean = false) {
        repository.getBannersDb2(isRefresh)
            .checkResult(
                onSuccess = {
                    _banners.value = it
                }
                , onError = {
                    LogUtils.dTag(DEBUG_TAG, "getBannersDb2 onError $it")
                }
            )
    }

    /**
     * 当一个请求结果，依赖另一个请求结果的时候，我们可以用 流的方式如下：
     *  以此类推，还可以 用  zip 操作符 对多个请求进行合并，以及 flatMapMerge、flatMapConcat 等。
     *  熟悉 RxJava 的你，分分钟钟可以上手的  （斜眼笑  `-` ）
     *
     *  @FlowPreview 代表可能以后存在Api函数变动
     *  @ExperimentalCoroutinesApi  代表目前可能存在不稳定的因素的函数
     *  @ObsoleteCoroutinesApi 可能存在被废弃的可能
     */
    @ExperimentalCoroutinesApi
    @FlowPreview
    fun requestScResult() {
        launchUI {
            launchFlow { repository.getBanners2() }
                .onStart { showLoadingView() }
                .flowOn(Dispatchers.IO)
                .onCompletion { showContentView() }
                .catch {
                    // 错误处理
                    val err = ExceptionHandle.handleException(it)
                    LogUtils.dTag(
                        DEBUG_TAG,
                        "requestScResult catch onError ${err.code}: ${err.errMsg}"
                    )
                }
                .collectLatest { result ->
                    withContext(Dispatchers.Main) {
                        result.doSuccess {
                            _banners.value = it
                            LogUtils.dTag(DEBUG_TAG, "requestScResult onError $it")
                        }
                        result.doFailure {
                            LogUtils.dTag(DEBUG_TAG, "requestScResult onError $it")
                        }
//                        result.checkResult({_banners.value = it},{})
                    }
                }
        }
    }


    fun autoRefresh() {
        launchUI {
            showLoadingView()
            getBannersDb2(true)
            getArticleList2(true)
            showContentView()
        }
    }

}